fix(server): reject Git-confirmed bare-root projects - #8646
walid-baharwal wants to merge 6 commits into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9ecd6caa04a03da511266a2370c6d113581566af. Configure here.
A worktree-only layout keeps a bare repository inside the root (commonly `<root>/.bare`) and checks every branch out as a sibling directory, so the root holds no working tree of its own. `git rev-parse --is-inside-work-tree` still answers true there, so the root was accepted as an ordinary repository and became the parent of every worktree: status reported each worktree as untracked, the diff view was scoped across all of them, and a thread's cwd spanned every checkout at once. Recognize the layout where a project is added and explain that a worktree directory inside it is what to add. Detection reads the `.git` file: a directory `.git` is an ordinary repository, and a `.git` file pointing outside the root is a linked worktree or a submodule. What remains is shared with `git init --separate-git-dir`, and git records nothing that separates the two — it writes no `core.worktree` for either — so two structural signals are required together: the git directory hosts linked worktrees, and it never staged anything of its own. A working tree that has committed has an index; a bare repository does not. Anything ambiguous is accepted, since wrongly refusing a valid root is worse than the misscoping this prevents. Containment is tested with a relative path so a root at the filesystem boundary is compared correctly. Fixes pingdotgg#8164
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a focused server validation fix that rejects only Git-confirmed bare repository roots during project addition while preserving ordinary repositories, worktrees, and converted roots. The implementation is localized and backed by broad edge-case and integration coverage. You can add or adjust custom eligibility rules. Learn more. |
9ecd6ca to
48fc1cd
Compare
|
Current-main audit for #8164, tested on 0dd5c64bc on September 4, 2026. The exact bare-clone, This PR still needs human review. The missing-index heuristic has outstanding counterexamples in the existing reviews, including a legitimate empty separate-git-dir repository. I have not verified the current PR head against those cases or the actual add/start UI path, so this comment is not a merge-readiness recommendation. Please keep the valid-layout controls when revising the classification rule. GPT 6 Astra via Codex in T3 Code. |
|
Thanks for the PR. We're not taking changes to the orchestration and provider layers right now: that part of the server is being rewritten for V2, and merging into the current code would either conflict with or be thrown away by that work. Closing for now. If this is still an issue once V2 lands, please reopen (or open a fresh PR against the new code) and we'll take a proper look. |

Human hold
This is a narrower project-add policy proposal for #8164, not a complete fix for the original report. Keep it unmerged until a maintainer approves rejecting Git-confirmed bare roots. Already-converted nonbare roots remain accepted. No initialization behavior changes are included.
Change
A root whose
.gitfile points to an embedded bare repository has no checkout of its own. Project add now rejects that root with an explanation and directs the user to an individual worktree. The check applies to CLI add and normalizedproject.createcommands.The original index heuristic rejected a valid unborn separate-git-dir checkout with a linked worktree and accepted a bare repository after
git read-tree --emptycreated an index. The correction asks Git for its current bare status instead. It makes one bounded query only for in-root gitdir pointers; ordinary repositories, directories without a pointer, and external linked-worktree pointers keep the no-process fast path. Query errors remain accepted rather than guessing.The shared pointer parser preserves native separators for the eligibility filter;
devHomekeeps its original backslash normalization. The final query gives Git the.gitfile itself, so Git—not the filter—resolves pointer syntax and trailing spaces.GIT_WORK_TREEis removed for this probe, and the explicit gitfile prevents an inheritedGIT_DIRfrom redirecting the query.Before and after
Real Git, production handlers and disposable SQLite fixtures on Linux. Original guard tested against main 931d41f9. Candidate includes main 2fb99a7a.
git initstore\namegitdir beside a different barestore/nameThe expanded WorkspacePaths tests fail in four cases against the old guard and pass with the correction. The POSIX backslash regression failed before the raw-parser repair. Three further review regressions failed on 2b1d4d88 and pass with the gitfile-query correction: malformed pointer headers beside an unrelated bare repo, a valid trailing-space gitdir beside a bare trimmed-name sibling, and inherited Git environment overrides. Controls cover both
GIT_WORK_TREEandGIT_DIR. CLI/SQLite tests verify that rejected roots create no project record and that valid or already-converted roots remain addable. The same fixtures exercise production command normalization.56 focused tests pass, including the Windows-style
devHomepointer control. Scoped types, lint, formatting and whitespace checks pass. This is nonvisual server validation; no native macOS client add/start evidence is claimed. At e80cb32c, all executed CI jobs, Macroscope Correctness/Approvability and Cursor Bugbot pass. All five review threads are resolved; there are no active change requests. Preview jobs and CodeRabbit's disabled automatic review are skipped. The watcher completed. The human policy hold and missing native add/start proof remain; this is not a complete fix for the original issue.Limits
core.bare=truein the Linux fixture. T3's existinginitRepositorychanged it to false, after which the detector accepted the parent and status listed sibling worktrees as untracked. This PR does not change that initialization path or repair existing projects.invalid_commandresponse.Original implementation by Walid Baharwal is preserved in 48fc1cd9; current main was merged without rewriting the author's history.
Correction and verification: GPT 6 Astra via Codex in T3 Code.
Note
Medium Risk
Changes project-creation validation and shells out to Git for some workspace roots; if Git is unavailable, bare layouts may still be accepted by design.
Overview
Project add now rejects workspace roots whose in-root
.gitfile points at an embedded bare repository, with a clear error directing users to add an individual worktree instead. The check runs onproject addand on normalizedproject.createcommands only; other callers still accept bare pointer roots after normalization.Detection replaces index/heuristic guards with a bounded
git rev-parse --is-bare-repositoryquery (viaensureNotBareRepositoryLayout) for eligible in-root gitdir pointers, while keeping a no-Git fast path for ordinary repos and external pointers. Git failures or spawn errors accept the root rather than block add.Shared
parseGitDirPointercentralizes.gitfile parsing;devHomeuses it for linked-worktree detection. Broad unit and CLI integration tests cover bare, separate-git-dir, worktree, converted, and edge-case layouts.Reviewed by Cursor Bugbot for commit e80cb32. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Reject bare-root Git repositories in
project-addand command normalizationensureNotBareRepositoryLayoutto theWorkspacePathsservice, which probes when.gitis a gitfile pointing strictly inside the normalized root and asks Git--is-bare-repository; nonzero or failed Git results are treated as not bare.projectAddMutationin project.ts and orchestrationnormalizeDispatchCommandin Normalizer.ts now call the check afternormalizeWorkspaceRoot, returning a newWorkspaceRootBareRepositoryLayoutError(mapped toOrchestrationDispatchCommandErrorin the normalizer).parseGitDirPointerutility in git.ts forgitdir:lines from.gitfiles;devHome.pointsAtLinkedWorktreenow uses it.trueresults do not trigger rejection.Macroscope summarized e80cb32.